/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2024. All rights reserved.
 * Description: version definiation for aipp config parser.
 */
#include "framework/model/aipp/aipp_config_parser.h"
#include "aipp_json_parser.h"

#include "framework/infra/log/log.h"

using namespace std;
using json = nlohmann::json;
namespace hiai {
static const string KEY_INPUT_PARA = "input_para";
static const string KEY_FORMAT = "format";
static const string KEY_SHAPE = "shape";
static const string KEY_SRC_IMAGE_SIZE_W = "src_image_size_w";
static const string KEY_SRC_IMAGE_SIZE_H = "src_image_size_h";
static const string KEY_SRC_IMAGE_SIZE_B = "src_image_size_b";

static const string KEY_SWITCH = "switch";

static const string KEY_CROP = "crop";
static const string KEY_CROP_START_POS_W = "start_pos_w";
static const string KEY_CROP_START_POS_H = "start_pos_h";
static const string KEY_CROP_SIZE_W = "size_w";
static const string KEY_CROP_SIZE_H = "size_h";

static const string KEY_RESIZE = "resize";
static const string KEY_RESIZE_OUTPUT_W = "resize_output_w";
static const string KEY_RESIZE_OUTPUT_H = "resize_output_h";

static const string KEY_PADDING = "padding";
static const string KEY_PADDING_LEFT_SIZE = "left_padding_size";
static const string KEY_PADDING_RIGHT_SIZE = "right_padding_size";
static const string KEY_PADDING_TOP_SIZE = "top_padding_size";
static const string KEY_PADDING_BOTTON_SIZE = "bottom_padding_size";
static const string KEY_PADDING_VALUE_CHN_0 = "padding_value_chn_0";
static const string KEY_PADDING_VALUE_CHN_1 = "padding_value_chn_1";
static const string KEY_PADDING_VALUE_CHN_2 = "padding_value_chn_2";
static const string KEY_PADDING_VALUE_CHN_3 = "padding_value_chn_3";

static const string KEY_CHANNEL_SWAP = "channnel_swap";
static const string KEY_RBUV_SWAP_SWITCH = "rbuv_swap_switch";
static const string KEY_AX_SWAP_SWITCH = "ax_swap_switch";

static const string KEY_CSC_MATRIX = "csc";
static const string KEY_CSC_MATRIX_R0C0 = "matrix_r0c0";
static const string KEY_CSC_MATRIX_R0C1 = "matrix_r0c1";
static const string KEY_CSC_MATRIX_R0C2 = "matrix_r0c2";
static const string KEY_CSC_MATRIX_R1C0 = "matrix_r1c0";
static const string KEY_CSC_MATRIX_R1C1 = "matrix_r1c1";
static const string KEY_CSC_MATRIX_R1C2 = "matrix_r1c2";
static const string KEY_CSC_MATRIX_R2C0 = "matrix_r2c0";
static const string KEY_CSC_MATRIX_R2C1 = "matrix_r2c1";
static const string KEY_CSC_MATRIX_R2C2 = "matrix_r2c2";
static const string KEY_CSC_INPUT_BIAS_0 = "input_bias_0";
static const string KEY_CSC_INPUT_BIAS_1 = "input_bias_1";
static const string KEY_CSC_INPUT_BIAS_2 = "input_bias_2";
static const string KEY_CSC_OUTPUT_BIAS_0 = "output_bias_0";
static const string KEY_CSC_OUTPUT_BIAS_1 = "output_bias_1";
static const string KEY_CSC_OUTPUT_BIAS_2 = "output_bias_2";

static const string KEY_CSC = "color_space_convertion";
static const string KEY_CSC_INPUT_FORMAT = "input_format";
static const string KEY_CSC_OUTPUT_FORMAT = "output_format";
static const string KEY_CSC_COLOR_SPACE = "color_space";

static const string KEY_DTC = "dtc";
static const string KEY_DTC_MEAN_CHN_0 = "mean_chn_0";
static const string KEY_DTC_MEAN_CHN_1 = "mean_chn_1";
static const string KEY_DTC_MEAN_CHN_2 = "mean_chn_2";
static const string KEY_DTC_MEAN_CHN_3 = "mean_chn_3";
static const string KEY_DTC_MIN_CHN_0 = "min_chn_0";
static const string KEY_DTC_MIN_CHN_1 = "min_chn_1";
static const string KEY_DTC_MIN_CHN_2 = "min_chn_2";
static const string KEY_DTC_MIN_CHN_3 = "min_chn_3";
static const string KEY_DTC_VAR_RECI_CHN_0 = "var_reci_chn_0";
static const string KEY_DTC_VAR_RECI_CHN_1 = "var_reci_chn_1";
static const string KEY_DTC_VAR_RECI_CHN_2 = "var_reci_chn_2";
static const string KEY_DTC_VAR_RECI_CHN_3 = "var_reci_chn_3";

static const string KEY_ROTATION = "rotation";
static const string KEY_ROTATION_ANGLE = "rotation_angle";

static const int INT16_MAX_VALUE = 32767;

static const map<string, hiai::ImageFormat> IMAGE_FORMAT_MAP = {
    {"YUV420SP_U8", hiai::ImageFormat::YUV420SP}, {"XRGB8888_U8", hiai::ImageFormat::XRGB8888},
    {"YUV400_U8", hiai::ImageFormat::YUV400}, {"ARGB8888_U8", hiai::ImageFormat::ARGB8888},
    {"YUYV_U8", hiai::ImageFormat::YUYV}, {"YUV422SP_U8", hiai::ImageFormat::YUV422SP},
    {"AYUV444_U8", hiai::ImageFormat::AYUV444}, {"RGB888_U8", hiai::ImageFormat::RGB888},
    {"BGR888_U8", hiai::ImageFormat::BGR888}, {"YUV444SP_U8", hiai::ImageFormat::YUV444SP},
    {"YVU444SP_U8", hiai::ImageFormat::YVU444SP}};

static const map<string, hiai::ImageColorSpace> COLOR_SPACE_MAP = {
    {"JPEG", hiai::ImageColorSpace::JPEG},
    {"BT_601_NARROW", hiai::ImageColorSpace::BT_601_NARROW},
    {"BT_601_FULL", hiai::ImageColorSpace::BT_601_FULL},
    {"BT_709_NARROW", hiai::ImageColorSpace::BT_709_NARROW}};

static const map<string, hiai::AiTensorImage_Format> IMAGE_FORMAT_MAP_LEGACY = {
    {"YUV420SP_U8", hiai::AiTensorImage_YUV420SP_U8}, {"XRGB8888_U8", hiai::AiTensorImage_XRGB8888_U8},
    {"YUV400_U8", hiai::AiTensorImage_YUV400_U8}, {"ARGB8888_U8", hiai::AiTensorImage_ARGB8888_U8},
    {"YUYV_U8", hiai::AiTensorImage_YUYV_U8}, {"YUV422SP_U8", hiai::AiTensorImage_YUV422SP_U8},
    {"AYUV444_U8", hiai::AiTensorImage_AYUV444_U8}, {"RGB888_U8", hiai::AiTensorImage_RGB888_U8},
    {"BGR888_U8", hiai::AiTensorImage_BGR888_U8}, {"YUV444SP_U8", hiai::AiTensorImage_YUV444SP_U8},
    {"YVU444SP_U8", hiai::AiTensorImage_YVU444SP_U8}};

bool operator==(const InputPara& inputPara1, const InputPara& inputPara2)
{
    if (inputPara1.format != inputPara2.format) {
        FMK_LOGW(
            "InputPara1's format %u is different from inputPara2's format %u.", inputPara1.format, inputPara2.format);
        return false;
    }
    if (inputPara1.shape.srcImageSizeW != inputPara2.shape.srcImageSizeW) {
        FMK_LOGW("InputPara1's srcImageSizeW %u is different from inputPara2's srcImageSizeW %u.",
            inputPara1.shape.srcImageSizeW, inputPara2.shape.srcImageSizeW);
        return false;
    }
    if (inputPara1.shape.srcImageSizeH != inputPara2.shape.srcImageSizeH) {
        FMK_LOGW("InputPara1's srcImageSizeH %u is different from inputPara2's srcImageSizeH %u.",
            inputPara1.shape.srcImageSizeH, inputPara2.shape.srcImageSizeH);
        return false;
    }

    return true;
}

bool AippConfigParser::ValidUIntFromJson(const json& s, const string& name, uint32_t& uValue)
{
    int value = 0;
    if (AippJsonParser::GetIntFromJson(s, name, value)) {
        if (value < 0) {
            FMK_LOGE("%s value %d is invalid, it should be positive number.", name.c_str(), value);
            return false;
        }
        uValue = static_cast<uint32_t>(value);
    } else {
        uValue = 0;
    }

    return true;
}

bool AippConfigParser::ValidInt16FromJson(const json& s, const string& name, int16_t& sValue)
{
    int value = 0;
    if (AippJsonParser::GetIntFromJson(s, name, value)) {
        if ((value < -INT16_MAX_VALUE) || (value > INT16_MAX_VALUE)) {
            FMK_LOGE("%s value %d is out of range.", name.c_str(), value);
            return false;
        }
        sValue = static_cast<int16_t>(value);
    } else {
        sValue = 0;
    }

    return true;
}

bool AippConfigParser::ValidImageFormat(const json& s, const string& name, hiai::AiTensorImage_Format& imageFormat)
{
    string format;
    if (!AippJsonParser::GetStringFromJson(s, name, format)) {
        FMK_LOGE("Get %s failed.", name.c_str());
        return false;
    }
    auto iter = IMAGE_FORMAT_MAP_LEGACY.find(format);
    if (iter == IMAGE_FORMAT_MAP_LEGACY.end()) {
        FMK_LOGE("%s value %s is invalid, it should be in image format map.", KEY_FORMAT.c_str(), format.c_str());
        return false;
    }
    imageFormat = iter->second;

    return true;
}

bool AippConfigParser::ValidImageFormat(const json& s, const string& name, hiai::ImageFormat& imageFormat)
{
    string format;
    if (!AippJsonParser::GetStringFromJson(s, name, format)) {
        FMK_LOGE("Get %s failed.", name.c_str());
        return false;
    }
    auto iter = IMAGE_FORMAT_MAP.find(format);
    if (iter == IMAGE_FORMAT_MAP.end()) {
        FMK_LOGE("%s value %s is invalid, it should be in image format map.", KEY_FORMAT.c_str(), format.c_str());
        return false;
    }
    imageFormat = iter->second;

    return true;
}

bool AippConfigParser::ParseInputParaLegacy(const json& s, InputPara& inputPara)
{
    json input;
    if (!AippJsonParser::GetNodeFromJson(s, KEY_INPUT_PARA, input)) {
        return false;
    }
    if (!ValidImageFormat(input, KEY_FORMAT, inputPara.format)) {
        return false;
    }

    json shape;
    if (!AippJsonParser::GetNodeFromJson(input, KEY_SHAPE, shape)) {
        return false;
    }
    if (!ValidUIntFromJson(shape, KEY_SRC_IMAGE_SIZE_W, inputPara.shape.srcImageSizeW)) {
        return false;
    }
    if (!ValidUIntFromJson(shape, KEY_SRC_IMAGE_SIZE_H, inputPara.shape.srcImageSizeH)) {
        return false;
    }

    return true;
}

bool AippConfigParser::ParseInputPara(const json& s, InputParaV2& inputPara)
{
    json input;
    if (!AippJsonParser::GetNodeFromJson(s, KEY_INPUT_PARA, input)) {
        return false;
    }
    if (!ValidImageFormat(input, KEY_FORMAT, inputPara.format)) {
        return false;
    }

    json shape;
    if (!AippJsonParser::GetNodeFromJson(input, KEY_SHAPE, shape)) {
        return false;
    }
    if (!AippJsonParser::GetIntFromJson(shape, KEY_SRC_IMAGE_SIZE_W, inputPara.shape.srcImageSizeW)) {
        inputPara.shape.srcImageSizeW = 0;
    }
    if (!AippJsonParser::GetIntFromJson(shape, KEY_SRC_IMAGE_SIZE_H, inputPara.shape.srcImageSizeH)) {
        inputPara.shape.srcImageSizeH = 0;
    }
    if (!AippJsonParser::GetIntFromJson(shape, KEY_SRC_IMAGE_SIZE_B, inputPara.shape.srcImageSizeB)) {
        inputPara.shape.srcImageSizeB = 0;
    }
    return true;
}

bool AippConfigParser::ParseCropPara(const json& crop, hiai::AippCropPara& cropPara)
{
    if (!AippJsonParser::GetBoolFromJson(crop, KEY_SWITCH, cropPara.switch_)) {
        FMK_LOGE("Parse switch from crop failed.");
        return false;
    }

    if (!cropPara.switch_) {
        FMK_LOGI("Crop para switch is false, close crop function.");
        return true;
    }

    if (!ValidUIntFromJson(crop, KEY_CROP_START_POS_W, cropPara.cropStartPosW)) {
        return false;
    }
    if (!ValidUIntFromJson(crop, KEY_CROP_START_POS_H, cropPara.cropStartPosH)) {
        return false;
    }

    if (!ValidUIntFromJson(crop, KEY_CROP_SIZE_W, cropPara.cropSizeW)) {
        return false;
    }
    if (!ValidUIntFromJson(crop, KEY_CROP_SIZE_H, cropPara.cropSizeH)) {
        return false;
    }

    return true;
}

bool AippConfigParser::ParseCropPara(const json& s, vector<hiai::AippCropPara>& vecCropPara)
{
    std::vector<json> vecCrop;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_CROP, vecCrop)) {
        for (json crop : vecCrop) {
            hiai::AippCropPara cropPara;
            if (!ParseCropPara(crop, cropPara)) {
                return false;
            }
            vecCropPara.push_back(cropPara);
        }
    }

    return true;
}

bool AippConfigParser::ParseResizePara(const json& resize, hiai::AippResizePara& resizePara)
{
    if (!AippJsonParser::GetBoolFromJson(resize, KEY_SWITCH, resizePara.switch_)) {
        FMK_LOGE("Parse switch from resize failed.");
        return false;
    }

    if (!resizePara.switch_) {
        FMK_LOGI("Resize para switch is false, close resize function.");
        return true;
    }

    if (!ValidUIntFromJson(resize, KEY_RESIZE_OUTPUT_W, resizePara.resizeOutputSizeW)) {
        return false;
    }
    if (!ValidUIntFromJson(resize, KEY_RESIZE_OUTPUT_H, resizePara.resizeOutputSizeH)) {
        return false;
    }
    return true;
}

bool AippConfigParser::ParseResizePara(const json& s, vector<hiai::AippResizePara>& vecResizePara)
{
    std::vector<json> vecResize;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_RESIZE, vecResize)) {
        for (json resize : vecResize) {
            hiai::AippResizePara resizePara;
            if (!ParseResizePara(resize, resizePara)) {
                return false;
            }
            vecResizePara.push_back(resizePara);
        }
    }

    return true;
}

bool AippConfigParser::ParsePaddingPara(const json& padding, hiai::AippPaddingPara& paddingPara)
{
    if (!AippJsonParser::GetBoolFromJson(padding, KEY_SWITCH, paddingPara.switch_)) {
        FMK_LOGE("Parse switch from padding failed.");
        return false;
    }

    if (!paddingPara.switch_) {
        FMK_LOGI("Padding para switch is false, close padding function.");
        return true;
    }

    if (!ValidUIntFromJson(padding, KEY_PADDING_LEFT_SIZE, paddingPara.paddingSizeLeft)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_RIGHT_SIZE, paddingPara.paddingSizeRight)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_TOP_SIZE, paddingPara.paddingSizeTop)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_BOTTON_SIZE, paddingPara.paddingSizeBottom)) {
        return false;
    }
    map<string, float&> paddingValMap = {
        {KEY_PADDING_VALUE_CHN_0, paddingPara.paddingValueChn0},
        {KEY_PADDING_VALUE_CHN_1, paddingPara.paddingValueChn1},
        {KEY_PADDING_VALUE_CHN_2, paddingPara.paddingValueChn2},
        {KEY_PADDING_VALUE_CHN_3, paddingPara.paddingValueChn3},
    };
    for (auto it = paddingValMap.begin(); it != paddingValMap.end(); it++) {
        if (!GetFloatFromJsonWithDefault(padding, it->first, it->second, 0.0)) {
            return false;
        }
    }

    return true;
}

bool AippConfigParser::ParsePaddingPara(const json& s, vector<hiai::AippPaddingPara>& vecPaddingPara)
{
    std::vector<json> vecPadding;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_PADDING, vecPadding)) {
        for (json padding : vecPadding) {
            hiai::AippPaddingPara paddingPara;
            if (!ParsePaddingPara(padding, paddingPara)) {
                return false;
            }
            vecPaddingPara.push_back(paddingPara);
        }
    }

    return true;
}

bool AippConfigParser::ParseChannelSwapPara(const json& s, hiai::AippChannelSwapPara& channelSwapPara)
{
    json channelSwap;
    if (AippJsonParser::GetNodeFromJson(s, KEY_CHANNEL_SWAP, channelSwap)) {
        if (!AippJsonParser::GetBoolFromJson(channelSwap, KEY_RBUV_SWAP_SWITCH, channelSwapPara.rbuvSwapSwitch)) {
            FMK_LOGE("Parse %s from channel_swap failed.", KEY_RBUV_SWAP_SWITCH.c_str());
            return false;
        }

        if (!AippJsonParser::GetBoolFromJson(channelSwap, KEY_AX_SWAP_SWITCH, channelSwapPara.axSwapSwitch)) {
            FMK_LOGE("Parse %s from channel_swap failed.", KEY_AX_SWAP_SWITCH.c_str());
            return false;
        }
    }
    return true;
}

bool AippConfigParser::ParseCscPara(const json& s, hiai::AippCscPara& cscPara)
{
    json csc;
    if (AippJsonParser::GetNodeFromJson(s, KEY_CSC_MATRIX, csc)) {
        if (!AippJsonParser::GetBoolFromJson(csc, KEY_SWITCH, cscPara.switch_)) {
            FMK_LOGE("Parse switch from csc failed.");
            return false;
        }
        if (!cscPara.switch_) {
            FMK_LOGI("Csc para switch is false, close csc function.");
            return true;
        }
        map<string, int32_t&> cscMatrixMap = {
            {KEY_CSC_MATRIX_R0C0, cscPara.matrixR0C0},
            {KEY_CSC_MATRIX_R0C1, cscPara.matrixR0C1},
            {KEY_CSC_MATRIX_R0C2, cscPara.matrixR0C2},
            {KEY_CSC_MATRIX_R1C0, cscPara.matrixR1C0},
            {KEY_CSC_MATRIX_R1C1, cscPara.matrixR1C1},
            {KEY_CSC_MATRIX_R1C2, cscPara.matrixR1C2},
            {KEY_CSC_MATRIX_R2C0, cscPara.matrixR2C0},
            {KEY_CSC_MATRIX_R2C1, cscPara.matrixR2C1},
            {KEY_CSC_MATRIX_R2C2, cscPara.matrixR2C2},
            {KEY_CSC_INPUT_BIAS_0, cscPara.inputBias0},
            {KEY_CSC_INPUT_BIAS_1, cscPara.inputBias1},
            {KEY_CSC_INPUT_BIAS_2, cscPara.inputBias2},
            {KEY_CSC_OUTPUT_BIAS_0, cscPara.outputBias0},
            {KEY_CSC_OUTPUT_BIAS_1, cscPara.outputBias1},
            {KEY_CSC_OUTPUT_BIAS_2, cscPara.outputBias2},
        };
        for (auto it = cscMatrixMap.begin(); it != cscMatrixMap.end(); it++) {
            if (!AippJsonParser::GetIntFromJson(csc, it->first, it->second)) {
                FMK_LOGE("Parse %s from csc failed.", it->first.c_str());
                return false;
            }
        }
    }
    return true;
}

bool AippConfigParser::GetInt16FromJsonWithDefault(const json& s, const string& name, int16_t& sValue, int16_t defValue)
{
    if (AippJsonParser::VarifyNodeInJson(s, name)) {
        if (!ValidInt16FromJson(s, name, sValue)) {
            return false;
        }
    } else {
        sValue = defValue;
    }
    return true;
}

bool AippConfigParser::GetFloatFromJsonWithDefault(const json& s, const string& name, float& sValue, float defValue)
{
    if (AippJsonParser::VarifyNodeInJson(s, name)) {
        if (!AippJsonParser::GetFloatFromJson(s, name, sValue)) {
            return false;
        }
    } else {
        sValue = defValue;
    }
    return true;
}

bool AippConfigParser::ParseDtcPara(const json& dtc, DtcConfig& dtcConfig)
{
    map<string, int16_t&> pixelMeanMap = {
        {KEY_DTC_MEAN_CHN_0, dtcConfig.dtcPara.pixelMeanChn0},
        {KEY_DTC_MEAN_CHN_1, dtcConfig.dtcPara.pixelMeanChn1},
        {KEY_DTC_MEAN_CHN_2, dtcConfig.dtcPara.pixelMeanChn2},
        {KEY_DTC_MEAN_CHN_3, dtcConfig.dtcPara.pixelMeanChn3},
    };
    for (auto it = pixelMeanMap.begin(); it != pixelMeanMap.end(); it++) {
        if (!GetInt16FromJsonWithDefault(dtc, it->first, it->second, 0)) {
            return false;
        }
    }
    map<string, float&> pixelMinVarMap = {
        {KEY_DTC_MIN_CHN_0, dtcConfig.dtcPara.pixelMinChn0},
        {KEY_DTC_MIN_CHN_1, dtcConfig.dtcPara.pixelMinChn1},
        {KEY_DTC_MIN_CHN_2, dtcConfig.dtcPara.pixelMinChn2},
        {KEY_DTC_MIN_CHN_3, dtcConfig.dtcPara.pixelMinChn3},
        {KEY_DTC_VAR_RECI_CHN_0, dtcConfig.dtcPara.pixelVarReciChn0},
        {KEY_DTC_VAR_RECI_CHN_1, dtcConfig.dtcPara.pixelVarReciChn1},
        {KEY_DTC_VAR_RECI_CHN_2, dtcConfig.dtcPara.pixelVarReciChn2},
        {KEY_DTC_VAR_RECI_CHN_3, dtcConfig.dtcPara.pixelVarReciChn3},
    };
    float pixelDefault = 0.0;
    for (auto it = pixelMinVarMap.begin(); it != pixelMinVarMap.end(); it++) {
        if (it->first.find("var_reci_chn") != it->first.npos) {
            pixelDefault = 1.0;
        }
        if (!GetFloatFromJsonWithDefault(dtc, it->first, it->second, pixelDefault)) {
            return false;
        }
    }
    dtcConfig.switch_ = true;

    return true;
}

bool AippConfigParser::ParseDtcPara(const json& s, vector<DtcConfig>& vecDtcConfig)
{
    std::vector<json> vecDtc;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_DTC, vecDtc)) {
        for (json dtc : vecDtc) {
            DtcConfig dtcConfig;
            if (!ParseDtcPara(dtc, dtcConfig)) {
                return false;
            }
            vecDtcConfig.push_back(dtcConfig);
        }
    }

    return true;
}

bool AippConfigParser::ParseCropPara(const json& crop, hiai::CropPara& cropPara, bool& isDynamicFunc)
{
    bool cropSwitch = false;
    if (!AippJsonParser::GetBoolFromJson(crop, KEY_SWITCH, cropSwitch)) {
        FMK_LOGE("Parse switch from crop failed.");
        return false;
    }

    if (!cropSwitch) {
        FMK_LOGI("Crop para switch is false, close crop function.");
        return true;
    }
    isDynamicFunc = true;

    if (!ValidUIntFromJson(crop, KEY_CROP_START_POS_W, cropPara.cropStartPosW)) {
        return false;
    }
    if (!ValidUIntFromJson(crop, KEY_CROP_START_POS_H, cropPara.cropStartPosH)) {
        return false;
    }

    if (!ValidUIntFromJson(crop, KEY_CROP_SIZE_W, cropPara.cropSizeW)) {
        return false;
    }
    if (!ValidUIntFromJson(crop, KEY_CROP_SIZE_H, cropPara.cropSizeH)) {
        return false;
    }

    return true;
}

bool AippConfigParser::ParseCropPara(const nlohmann::json& s, hiai::MultiCropPara& vecCropPara, bool& isDynamicFunc)
{
    std::vector<json> vecCrop;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_CROP, vecCrop)) {
        uint32_t index = 0;
        for (json crop : vecCrop) {
            hiai::CropPara cropPara;
            if (!ParseCropPara(crop, cropPara, isDynamicFunc)) {
                return false;
            }
            cropPara.batchIndex = index;
            vecCropPara.cropParas.push_back(cropPara);
            index++;
        }
    }

    return true;
}

bool AippConfigParser::ParseResizePara(const json& resize, hiai::ResizePara& resizePara, bool& isDynamicFunc)
{
    bool resizeSwitch = false;
    if (!AippJsonParser::GetBoolFromJson(resize, KEY_SWITCH, resizeSwitch)) {
        FMK_LOGE("Parse switch from resize failed.");
        return false;
    }

    if (!resizeSwitch) {
        FMK_LOGI("Resize para switch is false, close resize function.");
        return true;
    }
    isDynamicFunc = true;
    if (!ValidUIntFromJson(resize, KEY_RESIZE_OUTPUT_W, resizePara.resizeOutputSizeW)) {
        return false;
    }
    if (!ValidUIntFromJson(resize, KEY_RESIZE_OUTPUT_H, resizePara.resizeOutputSizeH)) {
        return false;
    }
    return true;
}

bool AippConfigParser::ParseResizePara(const nlohmann::json& s, hiai::MultiResizePara& vecResizePara,
    bool& isDynamicFunc)
{
    std::vector<json> vecResize;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_RESIZE, vecResize)) {
        uint32_t index = 0;
        for (json resize : vecResize) {
            hiai::ResizePara resizePara;
            if (!ParseResizePara(resize, resizePara, isDynamicFunc)) {
                return false;
            }
            resizePara.batchIndex = index;
            vecResizePara.resizeParas.push_back(resizePara);
            index++;
        }
    }

    return true;
}

bool AippConfigParser::ParsePaddingPara(const json& padding, hiai::PadPara& paddingPara, bool& isDynamicFunc)
{
    bool paddingSwitch = true;
    if (!AippJsonParser::GetBoolFromJson(padding, KEY_SWITCH, paddingSwitch)) {
        FMK_LOGE("Parse switch from padding failed.");
        return false;
    }

    if (!paddingSwitch) {
        FMK_LOGI("Padding para switch is false, close padding function.");
        return true;
    }
    isDynamicFunc = true;
    if (!ValidUIntFromJson(padding, KEY_PADDING_LEFT_SIZE, paddingPara.paddingSizeLeft)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_RIGHT_SIZE, paddingPara.paddingSizeRight)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_TOP_SIZE, paddingPara.paddingSizeTop)) {
        return false;
    }
    if (!ValidUIntFromJson(padding, KEY_PADDING_BOTTON_SIZE, paddingPara.paddingSizeBottom)) {
        return false;
    }
    map<string, float&> paddingValMap = {
        {KEY_PADDING_VALUE_CHN_0, paddingPara.paddingValueChn0},
        {KEY_PADDING_VALUE_CHN_1, paddingPara.paddingValueChn1},
        {KEY_PADDING_VALUE_CHN_2, paddingPara.paddingValueChn2},
        {KEY_PADDING_VALUE_CHN_3, paddingPara.paddingValueChn3},
    };
    for (auto it = paddingValMap.begin(); it != paddingValMap.end(); it++) {
        if (!GetFloatFromJsonWithDefault(padding, it->first, it->second, 0)) {
            return false;
        }
    }

    return true;
}

bool AippConfigParser::ParsePaddingPara(const nlohmann::json& s, hiai::MultiPadPara& vecPaddingPara,
    bool& isDynamicFunc)
{
    std::vector<json> vecPadding;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_PADDING, vecPadding)) {
        uint32_t index = 0;
        for (json padding : vecPadding) {
            hiai::PadPara paddingPara;
            if (!ParsePaddingPara(padding, paddingPara, isDynamicFunc)) {
                return false;
            }
            paddingPara.batchIndex = index;
            vecPaddingPara.padParas.push_back(paddingPara);
            index++;
        }
    }

    return true;
}

bool AippConfigParser::ParseChannelSwapPara(const json& s, hiai::ChannelSwapPara& channelSwapPara, bool& isDynamicFunc)
{
    isDynamicFunc = false;
    json channelSwap;
    if (AippJsonParser::GetNodeFromJson(s, KEY_CHANNEL_SWAP, channelSwap)) {
        if (!AippJsonParser::GetBoolFromJson(channelSwap, KEY_RBUV_SWAP_SWITCH, channelSwapPara.rbuvSwapSwitch)) {
            FMK_LOGE("Parse %s from channel_swap failed.", KEY_RBUV_SWAP_SWITCH.c_str());
            return false;
        }

        if (!AippJsonParser::GetBoolFromJson(channelSwap, KEY_AX_SWAP_SWITCH, channelSwapPara.axSwapSwitch)) {
            FMK_LOGE("Parse %s from channel_swap failed.", KEY_AX_SWAP_SWITCH.c_str());
            return false;
        }
        if (channelSwapPara.rbuvSwapSwitch || channelSwapPara.axSwapSwitch) {
            isDynamicFunc = true;
        }
    }
    return true;
}

bool AippConfigParser::ValidColorSpace(const nlohmann::json& s, const std::string& name,
    hiai::ImageColorSpace& imageColorSpace)
{
    string colorSpace;
    if (!AippJsonParser::GetStringFromJson(s, name, colorSpace)) {
        FMK_LOGE("Get %s failed.", name.c_str());
        FMK_LOGE("Get %s failed.", name.c_str());
        return false;
    }
    auto iter = COLOR_SPACE_MAP.find(colorSpace);
    if (iter == COLOR_SPACE_MAP.end()) {
        FMK_LOGE("%s value %s is invalid, it should be in color space map.",
            KEY_CSC_COLOR_SPACE.c_str(), colorSpace.c_str());
        return false;
    }
    imageColorSpace = iter->second;

    return true;
}

bool AippConfigParser::ParseCscPara(const nlohmann::json& s, hiai::CscPara& cscPara, bool& isDynamicFunc)
{
    json csc;
    if (AippJsonParser::GetNodeFromJson(s, KEY_CSC, csc)) {
        bool cscParaSwitch = false;
        if (!AippJsonParser::GetBoolFromJson(csc, KEY_SWITCH, cscParaSwitch)) {
            FMK_LOGE("Parse switch from csc failed.");
            return false;
        }
        if (!cscParaSwitch) {
            FMK_LOGI("Csc para switch is false, close csc function.");
            return true;
        }
        isDynamicFunc = true;

        if (!ValidImageFormat(csc, KEY_CSC_INPUT_FORMAT, cscPara.imageFormat)) {
            return false;
        }
        if (!ValidImageFormat(csc, KEY_CSC_OUTPUT_FORMAT, cscPara.outputFormat)) {
            return false;
        }
        if (!ValidColorSpace(csc, KEY_CSC_COLOR_SPACE, cscPara.imageColorSpace)) {
            return false;
        }
    }
    return true;
}

bool AippConfigParser::ParseDtcParams(const json& dtc, hiai::DtcPara& dtcPara)
{
    map<string, int16_t&> pixelMeanMap = {
        {KEY_DTC_MEAN_CHN_0, dtcPara.pixelMeanChn0},
        {KEY_DTC_MEAN_CHN_1, dtcPara.pixelMeanChn1},
        {KEY_DTC_MEAN_CHN_2, dtcPara.pixelMeanChn2},
        {KEY_DTC_MEAN_CHN_3, dtcPara.pixelMeanChn3},
    };
    for (auto it = pixelMeanMap.begin(); it != pixelMeanMap.end(); it++) {
        if (!GetInt16FromJsonWithDefault(dtc, it->first, it->second, 0)) {
            return false;
        }
    }
    map<string, float&> pixelMinVarMap = {
        {KEY_DTC_MIN_CHN_0, dtcPara.pixelMinChn0},
        {KEY_DTC_MIN_CHN_1, dtcPara.pixelMinChn1},
        {KEY_DTC_MIN_CHN_2, dtcPara.pixelMinChn2},
        {KEY_DTC_MIN_CHN_3, dtcPara.pixelMinChn3},
        {KEY_DTC_VAR_RECI_CHN_0, dtcPara.pixelVarReciChn0},
        {KEY_DTC_VAR_RECI_CHN_1, dtcPara.pixelVarReciChn1},
        {KEY_DTC_VAR_RECI_CHN_2, dtcPara.pixelVarReciChn2},
        {KEY_DTC_VAR_RECI_CHN_3, dtcPara.pixelVarReciChn3},
    };
    float pixelDefault = 0.0;
    for (auto it = pixelMinVarMap.begin(); it != pixelMinVarMap.end(); it++) {
        if (it->first.find("var_reci_chn") != it->first.npos) {
            pixelDefault = 1.0;
        }
        if (!GetFloatFromJsonWithDefault(dtc, it->first, it->second, pixelDefault)) {
            return false;
        }
    }

    return true;
}

bool AippConfigParser::ParseDtcPara(const json& dtc, hiai::DtcPara& dtcPara, bool& isDynamicFunc)
{
    if (!ParseDtcParams(dtc, dtcPara)) {
        return false;
    }
    isDynamicFunc = true; // aipp_config只要配置dtc参数就是dtc动态

    return true;
}

bool AippConfigParser::ParseDtcPara(const nlohmann::json& s, DtcConfigV2& vecDtcConfig, bool& isDynamicFunc)
{
    std::vector<json> vecDtc;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_DTC, vecDtc)) {
        uint32_t index = 0;
        for (json dtc : vecDtc) {
            hiai::DtcPara dtcPara;
            if (!ParseDtcPara(dtc, dtcPara, isDynamicFunc)) {
                return false;
            }
            dtcPara.batchIndex = index;
            vecDtcConfig.switch_ = true;
            vecDtcConfig.dtcPara.dtcParas.push_back(dtcPara);
            index++;
        }
    }

    return true;
}

bool AippConfigParser::ParseRotateParaPara(const nlohmann::json& s, hiai::RotatePara& rotatePara, bool& isDynamicFunc)
{
    bool rotateParaSwitch = false;
    if (!AippJsonParser::GetBoolFromJson(s, KEY_SWITCH, rotateParaSwitch)) {
        FMK_LOGE("Parse switch from rotatePara failed.");
        return false;
    }
    if (!rotateParaSwitch) {
        FMK_LOGI("rotate para switch is false, close rotation function.");
        return true;
    }
    isDynamicFunc = true;
    if (!GetFloatFromJsonWithDefault(s, KEY_ROTATION_ANGLE, rotatePara.rotationAngle, 0.0)) {
        return false;
    }
    return true;
}

bool AippConfigParser::ParseRotateParaPara(const nlohmann::json& s, hiai::MultiRotatePara& vecRotateConfig,
    bool& isDynamicFunc)
{
    std::vector<json> vecRotate;
    if (AippJsonParser::GetNodeListFromJson(s, KEY_ROTATION, vecRotate)) {
        uint32_t index = 0;
        for (json rotate : vecRotate) {
            hiai::RotatePara rotatePara;
            if (!ParseRotateParaPara(rotate, rotatePara, isDynamicFunc)) {
                return false;
            }
            rotatePara.batchIndex = index;
            vecRotateConfig.rotateParas.push_back(rotatePara);
            index++;
        }
    }

    return true;
}

bool AippConfigParser::ParseConfig(const string& file, AippConfigV2& aippConfig)
{
    aippConfig.config = true;
    json j;
    if (!AippJsonParser::ReadFileToJson(file, j)) {
        FMK_LOGE("read file %s failed.", file.c_str());
        return false;
    }

    if (!ParseInputPara(j, aippConfig.inputPara)) {
        FMK_LOGE("Parse input parameter failed.");
        return false;
    }

    bool isDynamicFunc = false;
    if (!ParseCropPara(j, aippConfig.vecCropPara, isDynamicFunc)) {
        FMK_LOGE("Parse crop parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;
    if (!ParseChannelSwapPara(j, aippConfig.channelSwapPara, isDynamicFunc)) {
        FMK_LOGE("Parse ChannelSwap parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;

    if (!ParseCscPara(j, aippConfig.cscPara, isDynamicFunc)) {
        FMK_LOGE("Parse CSC parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;

    if (!ParseResizePara(j, aippConfig.vecResizePara, isDynamicFunc)) {
        FMK_LOGE("Parse resize parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;

    if (!ParseDtcPara(j, aippConfig.vecDtcConfig, isDynamicFunc)) {
        FMK_LOGE("Parse DTC parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;

    if (!ParseRotateParaPara(j, aippConfig.vecRotatePara, isDynamicFunc)) {
        FMK_LOGE("Parse rotate parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    isDynamicFunc = false;

    if (!ParsePaddingPara(j, aippConfig.vecPaddingPara, isDynamicFunc)) {
        FMK_LOGE("Parse padding parameter failed.");
        return false;
    }
    aippConfig.isDynamicFunc.push_back(isDynamicFunc);
    return true;
}

bool AippConfigParser::ParseConfigLegacy(const string& file, AippConfig& aippConfig)
{
    aippConfig.config = true;
    json j;
    if (!AippJsonParser::ReadFileToJson(file, j)) {
        FMK_LOGE("read file %s failed.", file.c_str());
        return false;
    }

    if (!ParseInputParaLegacy(j, aippConfig.inputPara)) {
        FMK_LOGE("Parse input parameter failed.");
        return false;
    }

    if (!ParseCropPara(j, aippConfig.vecCropPara)) {
        FMK_LOGE("Parse crop parameter failed.");
        return false;
    }

    if (!ParseResizePara(j, aippConfig.vecResizePara)) {
        FMK_LOGE("Parse resize parameter failed.");
        return false;
    }

    if (!ParsePaddingPara(j, aippConfig.vecPaddingPara)) {
        FMK_LOGE("Parse padding parameter failed.");
        return false;
    }

    if (!ParseChannelSwapPara(j, aippConfig.channelSwapPara)) {
        FMK_LOGE("Parse ChannelSwap parameter failed.");
        return false;
    }

    if (!ParseCscPara(j, aippConfig.cscPara)) {
        FMK_LOGE("Parse CSC parameter failed.");
        return false;
    }

    if (!ParseDtcPara(j, aippConfig.vecDtcConfig)) {
        FMK_LOGE("Parse DTC parameter failed.");
        return false;
    }
    return true;
}
}
